<template>
  <div
:style="{
      width: typeof width === 'number' ? width + 'px' : width,
      height: '100%',
    }"
v-loading="loading">
    <div v-if="$slots.search" ref="header" class="search-div w100">
      <slot name="search" />
    </div>
    <el-row v-if="$slots.toolbar" ref="toolbar" class="left ml5 mt5">
      <el-col :span="24">
        <slot name="toolbar" />
      </el-col>
    </el-row>
    <el-main class="p5 wh100">
      <el-table
        ref="zl_table"
        v-bind="$attrs"
        v-on="$listeners"
        :height="myHeight"
        :max-height="maxHeight"
        :border="border"
        :stripe="stripe"
        tooltip-effect="light"
        :default-expand-all="defaultExpandAll"
        :default-sort="defaultSort"
        :data="tableData"
        class="w100"
        @select="select"
        @select-all="selectAll"
        @selection-change="selectChange"
        @sort-change="sortChange"
      >
        <slot name="cols" />

        <template slot="empty">
          <el-empty :image-size="100" />
        </template>
      </el-table>
    </el-main>
    <el-footer class="w-footer left">
      <el-pagination
        :current-page="pageNum"
        :page-sizes="[10, 20, 30, 50, 100]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @size-change="changeSize"
        @current-change="changePage"
      />
    </el-footer>

  </div>
</template>

<script>
import request from '@/utils/request'
import Cookies from 'js-cookie'
/**
 * 使用window.localstorage做前端缓存
 */
const pageSizeCache = 'pageSizeCache'
// eslint-disable-next-line no-unused-vars
const pageSizeCacheFlag = 'pageSizeCacheFlag'

export default {
  name: 'ZlTable',
  props: {
    url: String,
    height: [String, Number],
    maxHeight: [String, Number],
    init: {
      type: Boolean,
      default: true
    },
    width: {
      type: String,
      default: '100%'
    },
    param: {
      type: Object,
      default: () => {}
    },
    defaultSort: Object,
    defaultExpandAll: {
      type: Boolean,
      default: false
    },
    border: {
      type: Boolean,
      default: false
    },
    stripe: {
      type: Boolean,
      default: false
    },
    method: {
      type: String,
      default: 'post'
    },
    actions: {
      type: Object,
      default: () => {}
    },
    // 是否自适应高度
    isInitTableHeight: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      loading: false,
      tableData: [],
      myHeight: this.height,
      total: 0,
      orderColumn:null,
      orderType: null,
      pageInfo: {

      },
      recordOldValue: { width: 0, height: 0 }, // 监听高宽
      pageSize: 10,
      pageNum: 1
    }
  },
  computed: {

  },
  created() {
    // 从缓存中获取当前table的pageSize，如果之前更改过，则会被缓存，此时优先取
    const size = this.getPageSizeCache()
    this.pageSize = size > 0 ? size : this.pageSize
  },
  mounted() {
    //!this.isInitTableHeight && this.initMutationObserver()
    // 添加样式和监听元素变化
    this.$nextTick(() => {
      this.initTableHeight()
      const that = this
      window.addEventListener('resize', function() {
        that.initTableHeight()
      })
    })
    if (this.init) {
      this.query()
    }
  },
  activated() {
    this.$nextTick(() => {
      this.$refs.zl_table.doLayout()
    })
  },
  methods: {
    toggleRowSelection(row,checked){
      this.$refs.zl_table.toggleRowSelection(row,checked)
    },
    getPageSizeCache: function() {
      const retObj = JSON.parse(window.localStorage.getItem(pageSizeCache))
      const key = this.url
      const flag = this.getCookie()
      if (!flag || flag === '') {
        // 表示没有cookie，但是ie下localstorage中还是会有数据，此时清除数据，返回0
        if (retObj !== null && retObj !== {}) {
          this.clearPageSizeCache()
        }
        return 0
      }
      if (
        retObj !== null &&
        key in retObj &&
        retObj[key] !== null &&
        retObj[key] !== ''
      ) {
        return retObj[key]
      }
      return 0
    },
    /**
     * 设置table的pageSize本地缓存
     */
    setPageSizeCache: function(value) {
      const retObj =
        JSON.parse(window.localStorage.getItem(pageSizeCache)) || {}
      retObj[this.url] = value
      const flag = this.getCookie()
      if (!flag || flag === '') {
        this.setCookie()
      }
      window.localStorage.setItem(pageSizeCache, JSON.stringify(retObj))
    },
    /**
     * 清除table的pageSize本地缓存
     */
    clearPageSizeCache: function() {
      window.localStorage.removeItem(pageSizeCache)
    },
    /**
     * 为pageSizeCacheFlag设置一个cookie，且过期时间设置为50年，
     * 然后如果手工调用清除缓存数据，这表示也要清除localstorage，在谷歌，火狐中可以，但是在ie中有问题，加一个判断一下
     * 所以通过判断是否有cookie，然后清除localstorage
     * Cookies具体方法API可见https://www.npmjs.com/package/js-cookie
     */
    setCookie: function() {
      Cookies.set(pageSizeCacheFlag, 'true', { expires: 365 * 50, path: '/' })
    },
    getCookie: function() {
      return Cookies.get(pageSizeCacheFlag)
    },
    /**
     * 滚动条滑动到指定位置
     * @param position number类型，滑动的位置
     */
    scrollTo: function(position) {
      const overflowY = this.$el.querySelector('.el-table__body-wrapper')
      if (!overflowY) {
        return
      }
      overflowY.scrollTop = position
    },
    // 监听元素边和和初始化表头和分页
    initMutationObserver() {
      // 初始化分页背景色
      // let pbgColor = this.$el.parentNode.style
      // console.log(pbgColor.backgroundColor);
      // 初始化布局
      const headerDom = this.$el.querySelector('.el-table__header-wrapper')
      const pagination = this.$el.querySelector('.el-pagination')
      const tableBody = this.$el.querySelector('.el-table__body-wrapper')
      headerDom.classList.add('header-sticky')
      pagination.classList.add('page-sticky')
      tableBody.style.overflowX = 'hidden'
      //       ::v-deep .el-table--scrollable-x .el-table__body-wrapper {
      //   overflow-x: hidden;
      // }

      // 初始化滚动条
      const MutationObserver =
        window.MutationObserver ||
        window.WebKitMutationObserver ||
        window.MozMutationObserver
      const element = this.$el.querySelector('.el-table__body')
      const options = {
        attributes: true,
        childList: true
      }
      // 在第一次的时候初始化
      this.recordOldValue.width = element.offsetWidth - 8 + 'px'
      // 创建MutationObserver实例，返回一个观察者对象
      this.observer = new MutationObserver((mutationRecoards, observer) => {
        this.recordOldValue.width =
          mutationRecoards[0].target.offsetWidth - 8 + 'px'
      })
      // 对观察者添加需要观察的元素，并设置需要观察元素的哪些方面
      this.observer.observe(element, options)
      // 监听滚动事件  滚动元素
      this.$refs.erScrollBar.addEventListener('scroll', this.erBarSrollEvent)
    },
    erBarSrollEvent(e) {
      const scrollLeft = e.target.scrollLeft
      // 获取bodydom
      this.$el.querySelector('.el-table__body-wrapper').scrollLeft = scrollLeft
    },
    initTableHeight() {
      if (!this.isInitTableHeight) {
        this.myHeight = null
        return
      }
      if (this.height) {
        this.myHeight = this.height
        return
      }

      this.$nextTick(() => {
        const clientHeight = document.body.clientHeight
        // 此处要判断一下this.$refs.table是否存在，因为在同时打开了多个带table的页面，然后关闭其中部分页面，最后调整窗口分辨率时会找不到已经关闭了的页面的table，会在控制台报红
        if (this.$refs.zl_table) {
          let parent = this.$refs.zl_table.$el.offsetParent
          if (parent === null) {
            // 无法获取隐藏元素的坐标相关值
            parent = this.$refs.zl_table.$el.parentElement
            while (parent) {
              if (parent.offsetParent) {
                break
              }
              parent = parent.parentElement
            }
          }
          let loop = 0
          let offetTop = this.$refs.zl_table.$el.offsetTop
          let offetparent = parent
          if (offetparent) {
            while (offetparent) {
              offetTop += offetparent.offsetTop
              offetparent = offetparent.offsetParent
              loop++
            }
            this.myHeight = clientHeight - offetTop + loop - 125
            // 由于其他打开的页面中的table，计算的offetTop一直为0，需要this.offetTop记录值
            this.offetTop = offetTop
          } else {
            this.myHeight = clientHeight - this.offetTop + loop - 125
          }
          this.$refs.zl_table.doLayout()
        }
      })
    },

    getSelected() {
      return this.$refs.zl_table.selection
    },
    select(v) {
      this.$emit('select', v)
    },
    selectAll(v) {
      this.$emit('selectAll', v)
    },
    selectChange(v) {
      this.$emit('selectChange', v)
    },
    sortChange(v) {
      //console.log(v)
      if(v.order != null){
        this.orderColumn = v.prop
        this.orderType = v.order
      }else{
        this.orderColumn = null
        this.orderType = null
      }
      this.query()
    },
    clearSelection() {
      this.$refs.zl_table.clearSelection()
    },
    checkRow(row, ck) {
      this.$refs.zl_table.toggleRowSelection(row, ck)
    },
    changePage(v) {
      this.pageNum = v
      this.refresh()
    },
    changeSize(v) {
      this.pageSize = v
      this.setPageSizeCache(v)
      this.refresh()
    },
    refresh() {
      this.loading = true
      if(this.orderType == null && this.defaultSort && this.defaultSort.prop){
        this.orderColumn = this.defaultSort.prop
        this.orderType = this.defaultSort.order
      }
      const p = { pageSize: this.pageSize, pageNum: this.pageNum,orderColumn: this.orderColumn ,orderType: this.orderType}
      this.$emit('beforeQuery')
      if (this.param) {
        for (const paramKey in this.param) {
          p[paramKey] = this.param[paramKey]
        }
      }
      const opt = {
        url: this.url,
        method: this.method
      }
      if (this.method === 'post') {
        opt.data = p
      } else {
        opt.params = p
      }
      request(opt).then((res) => {
        const list = res.list
        this.total = res.total
        this.pageInfo = res.pageInfo

        this.tableData = list
        this.loading = false
        this.$emit('afterQuery', list)
      }).catch(() => {
        this.loading = false
      })
    },
    query() {
      this.pageNum = 1
      this.refresh()
    }
  }
}
</script>

<style scoped>
  .search-div{
    line-height: 30px;height: auto;
  }
  .el-pagination{
    height: 30px;
  }
</style>
